<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { RvtLoader } from '../services/rvtLoader'
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min.js'

const containerRef = ref(null)
const selectedObject = ref(null)
const autoRotate = ref(false)
const wireframe = ref(false)
const showAxes = ref(true)
const showGrid = ref(true)
const isAnimating = ref(false)

// 存储场景对象
let scene = null
let camera = null
let renderer = null
let controls = null
let currentModel = null
let animationFrameId = null
let axesHelper = null
let gridHelper = null
let previousMaterial = null
let raycaster = null
let mouse = null

// 添加点击坐标存储
const clickPosition = ref(null)

// 动画相关变量
let currentTime = 0
const animationSpeed = 0.02
const animatableParts = new Map()

// 识别可动画部件
const identifyAnimatableParts = (model) => {
  if (!model) return
  
  let object3 = null
  let object25 = null
  
  // 第一次遍历找到object_3和object_25
  model.traverse((child) => {
    if (child.isMesh) {
      const name = child.name.toLowerCase()
      if (name === 'object_3') {
        object3 = child
      } else if (name === 'object_25') {
        object25 = child
      }
    }
  })
  
  // 计算肩关节位置
  let shoulderJointPosition = null
  if (object3 && object25) {
    // 获取两个物体的包围盒
    const box3 = new THREE.Box3().setFromObject(object3)
    const box25 = new THREE.Box3().setFromObject(object25)
    
    // 找到两个包围盒的相交区域
    const intersection = new THREE.Box3()
    intersection.copy(box3).intersect(box25)
    
    // 如果包围盒相交，使用相交区域的中心点
    if (!intersection.isEmpty()) {
      shoulderJointPosition = intersection.getCenter(new THREE.Vector3())
      
    } else {
      // 如果包围盒不相交，找到最近的点
      const center3 = box3.getCenter(new THREE.Vector3())
      const center25 = box25.getCenter(new THREE.Vector3())
      
      // 获取object_3朝向object_25的方向
      const direction = center25.clone().sub(center3).normalize()
      
      // 在object_3边界上找到最近的点
      const point3 = new THREE.Vector3()
      box3.clampPoint(center25, point3)
      
      // 在object_25边界上找到最近的点
      const point25 = new THREE.Vector3()
      box25.clampPoint(center3, point25)
      
      // 取两个最近点的中点作为关节位置
      shoulderJointPosition = point3.clone().add(point25).multiplyScalar(0.5)
      
      // 微调位置（根据实际模型的特点调整）
      shoulderJointPosition.y += 0.1  // 稍微向上调整
      shoulderJointPosition.x += (object3.position.x < object25.position.x ? 0.1 : -0.1)  // 根据左右手调整

      // {x: '1.665', y: '-0.171', z: '3.351'}
      // shoulderJointPosition.x = 1.665
      // shoulderJointPosition.y = -0.171
      // shoulderJointPosition.z = 3.351
    }
    
    console.log('找到肩关节位置:', shoulderJointPosition)
  }
  
  // 第二次遍历设置动画部件
  model.traverse((child) => {
    if (child.isMesh) {
      const name = child.name.toLowerCase()
      
      // 匹配特定的部件名称模式
      if (
        name=='object_1'||   // 手臂部件
        name=='object_29'||  // 手臂部件
        name=='object_18'||  // 手臂部件
        name=='object_19'||  // 手臂部件
        name=='object_20'||  // 手臂部件
        name=='object_4' ||  // 手臂部件
        name=='object_21' || // 右手臂部件
        name=='object_22' || // 右手臂部件
        name=='object_23' || // 右手臂部件
        name=='object_30' || // 右手臂部件
        name=='object_25' || // 右手臂部件
        name=='object_26'    // 右手臂部件
      ) {
        // 保存原始状态
        child.userData.originalRotation = child.rotation.clone()
        child.userData.originalPosition = child.position.clone()
        child.userData.originalMatrix = child.matrix.clone()
        child.userData.shoulderJointPosition = shoulderJointPosition
        
        // 根据部件类型设置不同的旋转参数
        if (
          name=='object_1' ||
          name=='object_29' ||
          name=='object_18' ||
          name=='object_19' ||
          name=='object_20'||
          name=='object_4'
        ) {
          // 左侧手臂部件
          child.userData.rotationAxis = 'x'
          child.userData.rotationSpeed = 2
          child.userData.rotationRange = Math.PI / 10
          child.userData.isLeftArm = true
        } else {
          // 右侧手臂部件
          child.userData.rotationAxis = 'x'
          child.userData.rotationSpeed = 2
          child.userData.rotationRange = Math.PI / 10
          child.userData.isRightArm = true
        }
        
        // 调试用：添加一个小球标记关节位置
        if (name === 'object_3' || name === 'object_25') {
          const jointMarker = new THREE.Mesh(
            new THREE.SphereGeometry(0.05, 8, 8),
            new THREE.MeshBasicMaterial({ color: 0xff0000 })
          )
          jointMarker.position.copy(shoulderJointPosition)
          model.add(jointMarker)
        }
        
        animatableParts.set(child.uuid, child)
        console.log('设置动画部件:', name)
      }
    }
  })
}

// 添加动画函数
const animateModel = () => {
  if (!currentModel || !isAnimating.value) return
  
  currentTime += animationSpeed
  
  // 只为可动画部件添加动画
  animatableParts.forEach((part) => {
    const axis = part.userData.rotationAxis
    const speed = part.userData.rotationSpeed
    
    // 根据设定的轴进行旋转
    switch (axis) {
      case 'x':
        part.rotation.x = currentTime * speed
        break
      case 'y':
        part.rotation.y = currentTime * speed
        break
      case 'z':
        part.rotation.z = currentTime * speed
        break
    }
  })
}

// 存储标签和标记
let labels = []
let markers = []

// 创建标签
const createLabel = (point) => {
  const label = document.createElement('div')
  label.className = 'data-label3d'
  label.innerHTML = `
    <div class="label-content">
      <div class="label-title">${point.name}</div>
      <div class="label-value">${point.value}${point.unit}</div>
    </div>
  `
  containerRef.value.appendChild(label)  // 改为添加到容器中而不是body
  return label
}

// 创建标记点几何体
const createMarker = (position) => {
  const geometry = new THREE.SphereGeometry(0.02, 16, 16) // 减小标记点大小
  const material = new THREE.MeshBasicMaterial({ 
    color: 0xff0000,
    transparent: true,
    opacity: 0.8
  })
  const marker = new THREE.Mesh(geometry, material)
  marker.position.copy(position)
  return marker
}

// 更新标签位置
const updateLabelPositions = () => {
  if (!camera || !scene || !renderer) return

  const tempV = new THREE.Vector3()
  
  labels.forEach((label, index) => {
    const marker = markers[index]
    if (!marker) return

    // 获取标记点的世界坐标
    marker.getWorldPosition(tempV)

    // 将世界坐标转换为屏幕坐标
    tempV.project(camera)

    // 转换为像素坐标
    const widthHalf = renderer.domElement.clientWidth / 2
    const heightHalf = renderer.domElement.clientHeight / 2
    const x = (tempV.x * widthHalf) + widthHalf
    const y = -(tempV.y * heightHalf) + heightHalf

    // 检查是否在相机前面
    if (tempV.z > 1) {
      label.style.display = 'none'
    } else {
      label.style.display = 'block'
      label.style.left = `${x}px`
      label.style.top = `${y}px`
    }
  })
}

// 更新数据
const updateData = () => {
  labels.forEach((label, index) => {
    const valueElement = label.querySelector('.label-value')
    if (!valueElement) return

    // 随机更新数值
    let newValue = ''
    if (valueElement.textContent.includes('°C')) {
      newValue = `${+(25 + Math.random() * 2).toFixed(1)}°C`
    } else if (valueElement.textContent.includes('%')) {
      newValue = `${+(55 + Math.random() * 10).toFixed(1)}%`
    } else if (valueElement.textContent.includes('kWh')) {
      newValue = `${+(400 + Math.random() * 100).toFixed(1)} kWh`
    }

    if (newValue) {
      valueElement.textContent = newValue
    }
  })
}

// 清理数据点
const clearDataPoints = () => {
  // 清理标签
  labels.forEach(label => {
    if (label && label.parentNode) {
      label.parentNode.removeChild(label)
    }
  })
  labels = []

  // 清理标记
  markers.forEach(marker => {
    if (marker && marker.parent) {
      marker.parent.remove(marker)
    }
  })
  markers = []
}

// 创建数据点
const createDataPoints = (model) => {
  if (!model) return

  // 计算模型边界
  const box = new THREE.Box3().setFromObject(model)
  const center = box.getCenter(new THREE.Vector3())
  const size = box.getSize(new THREE.Vector3())

  // 定义数据点
  const dataPoints = [
    // {
    //   position: new THREE.Vector3(
    //     center.x,
    //     center.y + size.y * 0.6,  // 调整位置
    //     center.z
    //   ),
    //   name: '温度传感器1',
    //   value: '25.5',
    //   unit: '°C'
    // },
    // {
    //   position: new THREE.Vector3(
    //     center.x,
    //     center.y + size.y * 0.1,  // 调整位置
    //     center.z
    //   ),
    //   name: '湿度传感器1',
    //   value: '60',
    //   unit: '%'
    // },
    // {
    //   position: new THREE.Vector3(
    //     center.x,
    //     center.y - size.y * 0.4,  // 调整位置
    //     center.z
    //   ),
    //   name: '能耗监测点1',
    //   value: '450.8',
    //   unit: 'kWh'
    // }
  ]

  // 创建标签和标记
  dataPoints.forEach(point => {
    const marker = createMarker(point.position)
    scene.add(marker)
    markers.push(marker)

    const label = createLabel(point)
    labels.push(label)
  })
}

// 处理模型点击
const handleModelClick = (event) => {
  if (!currentModel) return

  // 计算鼠标位置
  const rect = event.target.getBoundingClientRect()
  const x = ((event.clientX - rect.left) / rect.width) * 2 - 1
  const y = -((event.clientY - rect.top) / rect.height) * 2 + 1

  // 创建射线
  const raycaster = new THREE.Raycaster()
  const mouse = new THREE.Vector2(x, y)
  raycaster.setFromCamera(mouse, camera)

  // 检测相交的对象
  const intersects = raycaster.intersectObject(currentModel, true)

  // 恢复之前选中对象的材质
  if (selectedObject.value && previousMaterial) {
    selectedObject.value.material = previousMaterial
  }

  if (intersects.length > 0) {
    const object = intersects[0].object
    selectedObject.value = object
    
    // 保存原始材质
    previousMaterial = object.material
    
    // 创建高亮材质
    const highlightMaterial = previousMaterial.clone()
    highlightMaterial.color.setHex(0xff0000)
    highlightMaterial.emissive.setHex(0x333333)
    
    // 应用高亮材质
    object.material = highlightMaterial

    // 记录点击位置的世界坐标
    const point = intersects[0].point
    clickPosition.value = {
      x: point.x.toFixed(3),
      y: point.y.toFixed(3),
      z: point.z.toFixed(3)
    }
    console.log('点击坐标:', clickPosition.value)
  } else {
    selectedObject.value = null
    previousMaterial = null
    clickPosition.value = null
  }
}

// 切换网格模式
const toggleWireframe = () => {
  if (!currentModel) return
  
  currentModel.traverse((child) => {
    if (child.isMesh) {
      child.material.wireframe = wireframe.value
    }
  })
}

// 切换坐标轴显示
const toggleAxes = () => {
  if (axesHelper) {
    axesHelper.visible = showAxes.value
  }
}

// 切换网格显示
const toggleGrid = () => {
  if (gridHelper) {
    gridHelper.visible = showGrid.value
  }
}

// 切换动画状态
const toggleAnimation = (event) => {
  isAnimating.value = event.target.checked
  if (!isAnimating.value) {
    // 停止动画时重置所有部件的旋转
    animatableParts.forEach((part) => {
      if (part.userData.originalRotation) {
        part.rotation.copy(part.userData.originalRotation)
      }
    })
  } else {
    // 开始动画时重置时间
    currentTime = 0
  }
}

// 设置预设视角
const setView = (preset) => {
  if (!currentModel || !controls) return

  const box = new THREE.Box3().setFromObject(currentModel)
  const center = box.getCenter(new THREE.Vector3())
  const size = box.getSize(new THREE.Vector3())
  const maxDim = Math.max(size.x, size.y, size.z)
  
  const direction = viewPresets[preset].clone()
  const position = center.clone().add(direction.multiplyScalar(maxDim * 2))
  
  camera.position.copy(position)
  camera.lookAt(center)
  controls.target.copy(center)
  controls.update()
}

// 重置视图
const resetView = () => {
  if (!currentModel || !controls) return
  
  const box = new THREE.Box3().setFromObject(currentModel)
  const center = box.getCenter(new THREE.Vector3())
  const size = box.getSize(new THREE.Vector3())
  
  const maxDim = Math.max(size.x, size.y, size.z)
  const fov = camera.fov * (Math.PI / 180)
  const cameraDistance = maxDim / (2 * Math.tan(fov / 2))
  
  camera.position.copy(center)
  camera.position.z += cameraDistance * 2
  camera.lookAt(center)
  
  controls.target.copy(center)
  controls.update()
}

// 模拟数据
const mockData = ref({
  temperature: 25.5,
  humidity: 60,
  energy: 450.8,
  occupancy: 85,
  airQuality: 'Good',
  lastUpdate: new Date().toLocaleString()
})

// 更新模拟数据
const updateMockData = () => {
  mockData.value = {
    temperature: +(25 + Math.random() * 2).toFixed(1),
    humidity: +(55 + Math.random() * 10).toFixed(1),
    energy: +(400 + Math.random() * 100).toFixed(1),
    occupancy: Math.floor(70 + Math.random() * 30),
    airQuality: ['Good', 'Moderate', 'Fair'][Math.floor(Math.random() * 3)],
    lastUpdate: new Date().toLocaleString()
  }
}

// 视角预设
const viewPresets = {
  front: new THREE.Vector3(0, 0, 1),
  back: new THREE.Vector3(0, 0, -1),
  left: new THREE.Vector3(-1, 0, 0),
  right: new THREE.Vector3(1, 0, 0),
  top: new THREE.Vector3(0, 1, 0),
  bottom: new THREE.Vector3(0, -1, 0)
}



// 动画循环
const animate = () => {
  animationFrameId = requestAnimationFrame(animate)
  
  if (autoRotate.value && currentModel) {
    currentModel.rotation.y += 0.01
  }

  // 执行自定义动画
  if (isAnimating.value && currentModel) {
    currentTime += animationSpeed
    
    // 更新所有部件
    animatableParts.forEach((part) => {
      if (!part.userData.shoulderJointPosition) return
      
      const speed = part.userData.rotationSpeed
      const range = part.userData.rotationRange
      
      // 计算摆动角度
      const rotation = Math.sin(currentTime * speed) * range
      
      // 创建变换矩阵
      const transformMatrix = new THREE.Matrix4()
      const rotationMatrix = new THREE.Matrix4()
      const translationMatrix = new THREE.Matrix4()
      const translationBackMatrix = new THREE.Matrix4()
      
      // 设置平移矩阵（到原点和回到肩关节位置）
      translationMatrix.makeTranslation(
        -part.userData.shoulderJointPosition.x,
        -part.userData.shoulderJointPosition.y,
        -part.userData.shoulderJointPosition.z
      )
      translationBackMatrix.makeTranslation(
        part.userData.shoulderJointPosition.x,
        part.userData.shoulderJointPosition.y,
        part.userData.shoulderJointPosition.z
      )
      
      // 根据部件类型设置旋转
      if (part.userData.isLeftArm) {
        // 左臂旋转方向相反
        rotationMatrix.makeRotationX(-rotation)
      } else if (part.userData.isRightArm) {
        rotationMatrix.makeRotationX(rotation)
      }
      
      // 组合变换矩阵：先平移到原点，再旋转，最后平移回去
      transformMatrix.multiply(translationBackMatrix)
      transformMatrix.multiply(rotationMatrix)
      transformMatrix.multiply(translationMatrix)
      
      // 应用变换
      part.matrix.copy(part.userData.originalMatrix)
      part.matrix.premultiply(transformMatrix)
      part.matrix.decompose(part.position, part.quaternion, part.scale)
    })
  }

  if (controls) {
    controls.update()
  }
  
  TWEEN.update()
  updateLabelPositions()
  if (renderer && scene && camera) {
    renderer.render(scene, camera)
  }
}

// 修改文件加载函数
const handleFileUpload = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  const fileExtension = file.name.split('.').pop().toLowerCase()
  
  const supportedFormats = ['gltf', 'glb', 'fbx', 'obj']
  if (!supportedFormats.includes(fileExtension)) {
    alert('请选择支持的文件格式：GLTF、GLB、FBX 或 OBJ')
    return
  }

  try {
    const loader = new RvtLoader()
    const model = await loader.loadRvtFile(file)
    
    // 清理当前场景
    if (currentModel) {
      scene.remove(currentModel)
      currentModel.traverse((child) => {
        if (child.isMesh) {
          child.geometry.dispose()
          if (child.material.dispose) {
            child.material.dispose()
          }
        }
      })
    }
    
    // 清理现有数据点
    clearDataPoints()
    
    // 设置新模型
    model.traverse((child) => {
      if (child.isMesh) {
        child.userData.originalMaterial = child.material.clone()
      }
    })
    
    scene.add(model)
    currentModel = model
    currentTime = 0 // 重置动画时间
    
    // 识别可动画部件
    identifyAnimatableParts(model)
    
    // 调整相机视角
    const box = new THREE.Box3().setFromObject(model)
    const center = box.getCenter(new THREE.Vector3())
    const size = box.getSize(new THREE.Vector3())
    
    const maxDim = Math.max(size.x, size.y, size.z)
    const fov = camera.fov * (Math.PI / 180)
    const cameraDistance = maxDim / (2 * Math.tan(fov / 2))
    
    camera.position.copy(center)
    camera.position.z += cameraDistance * 2
    camera.lookAt(center)
    
    controls.target.copy(center)
    controls.update()

    // 创建新的数据点
    createDataPoints(model)

  } catch (error) {
    console.error('加载模型时出错:', error)
    alert('加载模型失败，请确保文件格式正确')
  }
}

onMounted(() => {
  if (!containerRef.value) return
  
  // 创建场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xf0f0f0)

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  )
  camera.position.set(5, 5, 5)
  camera.lookAt(0, 0, 0)

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ 
    antialias: true,
    alpha: true
  })
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFSoftShadowMap
  containerRef.value.appendChild(renderer.domElement)

  // 添加轨道控制器
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.05

  // 添加网格地面
  gridHelper = new THREE.GridHelper(10, 10)
  scene.add(gridHelper)

  // 添加坐标轴
  axesHelper = new THREE.AxesHelper(5)
  scene.add(axesHelper)

  // 添加环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.add(ambientLight)

  // 添加平行光
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(10, 10, 10)
  directionalLight.castShadow = true
  directionalLight.shadow.mapSize.width = 2048
  directionalLight.shadow.mapSize.height = 2048
  scene.add(directionalLight)

  // 添加点击事件监听器
  renderer.domElement.addEventListener('click', handleModelClick)

  // 处理窗口大小变化
  const handleResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
  window.addEventListener('resize', handleResize)

  // 开始动画循环
  animate()

  // 启动数据更新
  setInterval(updateData, 5000)

  // 注册清理函数
  onUnmounted(() => {
    window.removeEventListener('resize', handleResize)
    renderer.domElement.removeEventListener('click', handleModelClick)
    if (animationFrameId) {
      cancelAnimationFrame(animationFrameId)
    }
    cleanup()
    
    // 清理标签
    clearDataPoints()
  })
})

// 清理函数
const cleanup = () => {
  if (currentModel) {
    scene.remove(currentModel)
    currentModel.traverse((child) => {
      if (child.isMesh) {
        child.geometry.dispose()
        if (child.material.dispose) {
          child.material.dispose()
        }
      }
    })
  }
  
  if (controls) {
    controls.dispose()
  }
  
  if (renderer) {
    renderer.dispose()
  }
  
  scene = null
  camera = null
  renderer = null
  controls = null
  currentModel = null
}
</script>

<template>
  <div class="scene-container">
    <div ref="containerRef" class="three-container" />
    <div class="control-panel">
      <div class="upload-container">
        <div class="upload-info">
          <p>支持的文件格式：.gltf, .glb, .fbx, .obj</p>
          <p>提示：加载大型文件可能需要一些时间</p>
        </div>
        <input type="file" accept=".gltf,.glb,.fbx,.obj" @change="handleFileUpload" />
      </div>
      
      <div class="controls">
        <div class="control-group">
          <h3>显示控制</h3>
          <label>
            <input type="checkbox" v-model="autoRotate" /> 自动旋转
          </label>
          <label>
            <input type="checkbox" v-model="wireframe" @change="toggleWireframe" /> 线框模式
          </label>
          <label>
            <input type="checkbox" v-model="showAxes" @change="toggleAxes" /> 显示坐标轴
          </label>
          <label>
            <input type="checkbox" v-model="showGrid" @change="toggleGrid" /> 显示网格
          </label>
          <label >
            <input 
              type="checkbox" 
              :checked="isAnimating" 
              @change="toggleAnimation"
            /> 运行动画
          </label>
        </div>
        
        <div class="control-group">
          <h3>视角控制</h3>
          <div class="view-buttons">
            <!-- <button @click="setView('front')">前视图</button>
            <button @click="setView('back')">后视图</button>
            <button @click="setView('left')">左视图</button>
            <button @click="setView('right')">右视图</button>
            <button @click="setView('top')">俯视图</button>
            <button @click="setView('bottom')">仰视图</button> -->
            <button @click="resetView">重置视图</button>
          </div>
        </div>
        
        <div v-if="selectedObject" class="control-group">
          <h3>选中对象信息</h3>
          <p>原始名称: {{ selectedObject.name }}</p>
          <p>处理后名称: {{ selectedObject.name?.toLowerCase() }}</p>
          <p>类型: {{ selectedObject.type }}</p>
          <p>位置: {{ selectedObject.position.toArray().map(n => n.toFixed(2)).join(', ') }}</p>
          <template v-if="clickPosition">
            <h4>点击坐标</h4>
            <p>X: {{ clickPosition.x }}</p>
            <p>Y: {{ clickPosition.y }}</p>
            <p>Z: {{ clickPosition.z }}</p>
          </template>
        </div>
      </div>
    </div>
    
    <!-- 数据展示面板 -->
    <div class="data-panel" v-if="1==0">
      <h3>实时数据监控</h3>
      <div class="data-grid">
        <div class="data-item">
          <div class="data-label">温度</div>
          <div class="data-value">{{ mockData.temperature }}°C</div>
        </div>
        <div class="data-item">
          <div class="data-label">湿度</div>
          <div class="data-value">{{ mockData.humidity }}%</div>
        </div>
        <div class="data-item">
          <div class="data-label">能耗</div>
          <div class="data-value">{{ mockData.energy }} kWh</div>
        </div>
        <div class="data-item">
          <div class="data-label">人员容量</div>
          <div class="data-value">{{ mockData.occupancy }}%</div>
        </div>
        <div class="data-item">
          <div class="data-label">空气质量</div>
          <div class="data-value">{{ mockData.airQuality }}</div>
        </div>
      </div>
      <div class="data-update-time">
        最后更新: {{ mockData.lastUpdate }}
      </div>
    </div>
  </div>
</template>

<style scoped>
.scene-container {
  width: 100%;
  height: 100%;
  position: relative;
}

.three-container {
  width: 100%;
  height: 100%;
}

.control-panel {
  position: absolute;
  top: 20px;
  left: 20px;
  background: rgba(255, 255, 255, 0.9);
  padding: 20px;
  border-radius: 8px;
  z-index: 1;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  max-width: 300px;
}

.upload-container {
  margin-bottom: 20px;
}

.upload-info {
  margin-bottom: 10px;
  font-size: 14px;
  color: #666;
}

.upload-info p {
  margin: 5px 0;
}

.controls {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.control-group {
  border-top: 1px solid #eee;
  padding-top: 15px;
}

.control-group h3 {
  margin: 0 0 10px 0;
  font-size: 16px;
  color: #333;
}

.control-group label {
  display: block;
  margin: 5px 0;
  color: #666;
  cursor: pointer;
}

.view-buttons {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.view-buttons button {
  padding: 8px;
  background: #4a90e2;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

.view-buttons button:hover {
  background: #357abd;
}

.view-buttons button:last-child {
  grid-column: span 2;
  background: #666;
}

.view-buttons button:last-child:hover {
  background: #555;
}

/* 数据面板样式 */
.data-panel {
  position: absolute;
  top: 20px;
  right: 20px;
  background: rgba(255, 255, 255, 0.9);
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  width: 300px;
}

.data-panel h3 {
  margin: 0 0 15px 0;
  font-size: 16px;
  color: #333;
  text-align: center;
}

.data-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 15px;
}

.data-item {
  background: #f5f5f5;
  padding: 12px;
  border-radius: 6px;
  text-align: center;
}

.data-label {
  font-size: 14px;
  color: #666;
  margin-bottom: 5px;
}

.data-value {
  font-size: 18px;
  font-weight: bold;
  color: #4a90e2;
}

.data-update-time {
  margin-top: 15px;
  text-align: center;
  font-size: 12px;
  color: #999;
}

/* 标签样式 */
:global(.data-label3d) {
  position: absolute;
  pointer-events: none;
  z-index: 10;
  transform: translate(-50%, -100%);  /* 居中并向上偏移 */
}

:global(.label-content) {
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 6px 10px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  margin-bottom: 5px;  /* 给标记点留出空间 */
}

:global(.label-title) {
  font-size: 11px;
  opacity: 0.8;
  margin-bottom: 2px;
}

:global(.label-value) {
  font-weight: bold;
  font-size: 13px;
}

.animation-control {
  margin-top: 10px;
  padding: 5px;
  background-color: #f0f0f0;
  border-radius: 4px;
  display: block;
}
</style> 